﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;

namespace ParticleFiltersDemo1
{
    public class Controller : ViewModelBase
    {
        public int particlesCount = 10;
        private Robot robot;
        private Board board;
        private ParticlesSet particleSet;

        public Controller()
        {
            this.board = new Board();
            this.robot = new Robot( 3, 3, 90, false, this.board );
            this.particleSet = new ParticlesSet( particlesCount, this.board );
        }

        public Robot Robot
        {
            get
            {
                return this.robot;
            }
            set
            {
                if ( this.robot == value )
                    return;

                this.robot = value;
                this.NotifyPropertyChanged( "Robot" );
            }
        }

        public ParticlesSet  Particles
        {
            get
            {
                return this.particleSet;
            }
            set
            {
                if ( this.particleSet == value )
                    return;

                this.particleSet = value;
                this.NotifyPropertyChanged( "Particles" );
            }
        }

        public void DoMagic()
        {
            Random random = new Random();

            while ( this.particleSet.isDone == false )
            {
                // move the robot
                robot.Move();

                // move the particles
                for (int i = 0; i < this.particlesCount; i++)
                {
                    particleSet.particles[i].AdvanceBy(robot.speed, robot.noisy);
                }

                ParticlesSet newSet = new ParticlesSet( this.particlesCount, this.board );
                Particle p;
                List<int> probabilityPoints = new List<int>();
                double eta = 0;

                
                //constructing helper array of all particles many times for helping choosing ones
                for ( int i = 0; i < this.particlesCount; i++ )
                {
                    int x = ( int )( this.particleSet.particles[i].weight * 100 );
                    for ( int j = 0; j < x; j++ )
                        probabilityPoints.Add( i );
                }

                int particlesNextToOpsticle = 0;
                //fething particles with replasment and counting particlesNextToOpsticle 
                for ( int i = 0; i < this.particlesCount; i++ )
                {
                    // TODO !!! probabilityPoints[]
                    p = particleSet.particles[ probabilityPoints[random.Next( 0, probabilityPoints.Count - 1 )]];
                    newSet.particles[i] = p;
                    if ( p.AdvanceBy( this.robot.speed, this.robot.noisy ) == false )
                    {
                        p.weight = 0;
                    }
                    if ( p.IsNextToObstacle )
                    {
                        particlesNextToOpsticle++;
                    }
                }
                this.particleSet = newSet;
                //calculating new weight of particles 
                if ( robot.IsNextToObstacle )
                {
                    for ( int i = 0; i < this.particlesCount; i++ )
                    {
                        if ( particleSet.particles[i].weight == 0 )
                        {
                            continue;
                        }
                        if ( particleSet.particles[i].IsNextToObstacle )
                        {
                            particleSet.particles[i].weight = 0.8 / particlesNextToOpsticle;
                        }
                        else
                        {
                            particleSet.particles[i].weight = 0.2 / ( particlesCount - particlesNextToOpsticle );
                        }
                    }
                }
                else
                {
                    for ( int i = 0; i < this.particlesCount; i++ )
                    {
                        if ( particleSet.particles[i].weight == 0 )
                        {
                            continue;
                        }
                        if ( !particleSet.particles[i].IsNextToObstacle )
                        {
                            particleSet.particles[i].weight = 0.8 / particlesNextToOpsticle;
                        }
                        else
                        {
                            particleSet.particles[i].weight = 0.2 / ( particlesCount - particlesNextToOpsticle );
                        }
                    }
                }

                
                // calculate particles weight

                // calculate meanpoint
                this.particleSet.ComputeMeanPoint( this.board );

            }
        }

    }
}
